﻿using Culvert_Help;
using NeXus;
using NeXus.BIMBase;
using NeXus.BIMBase.Core;
using NeXus.BIMBase.Data;
using NeXus.BIMBase.SolidCore;
using NeXus.p3d;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static NeXus.p3d.GeCurveArray;

namespace checc_baseTools
{
    public class CheccWingWall
    {
        //八字墙最高截面高度S
        public static double S = 0;
        //八字墙最高截面与最低截面的法线距离G(cm)
        public static double G = 0;
        //翼墙夹角宽度
        public static double T1 = 0;
        public static double T2 = 0;
        //翼墙近洞头外延点(最高点)
        public static double C1 = 0;
        //翼墙远洞头外延点(最低点)
        public static double C2 = 0;
        /// <summary>
        /// 创建洞口右侧翼墙
        /// </summary>
        /// <param name="checcWingWallData">八字墙</param>
        /// <param name="coverThickness">盖板厚</param>
        /// <param name="exceedsHeight">端墙超度高度</param>
        /// <param name="angle">角度</param>
        public static Tuple<BPGraphics, GePoint3dCollection, Dictionary<string, double>> CreateRightCulvert(CheccWingWallData checcWingWallData, double coverThickness, double exceedsHeight)
        {
            BPProject project = BPApplication.getInstance().getProjectManager().getMainProject();
            BPModelBase model = project.getActiveModel();
            //八字墙最高截面高度S
            S = checcWingWallData.Distance_H + coverThickness + exceedsHeight;
            //八字墙最高截面与最低截面的法线距离G(cm)
            G = (S - checcWingWallData.H_min) * checcWingWallData.Slope_subgrade;
            //翼墙夹角宽度
            T1 = G * Math.Tan(Math.Abs(checcWingWallData.Angle_Favorable) * Math.PI / 180);

            //翼墙顶面点
            GePoint3dCollection top = new GePoint3dCollection()
            {
                new GePoint3d(0, checcWingWallData.Distance_W /2, S),
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1, checcWingWallData.H_min),
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1 + checcWingWallData.W_topWall, checcWingWallData.H_min),
                new GePoint3d(0, checcWingWallData.Distance_W /2 + checcWingWallData.W_topWall, S),
            };
            //翼墙近洞头外延点(最高点)
            C1 = S / checcWingWallData.Slope_outerVerticalWall + checcWingWallData.W_topWall;
            //翼墙远洞头外延点(最低点)
            C2 = checcWingWallData.H_min / checcWingWallData.Slope_outerVerticalWall + checcWingWallData.W_topWall;
            //翼墙低面点
            GePoint3dCollection bot = new GePoint3dCollection()
            {
                new GePoint3d(0, checcWingWallData.Distance_W /2, 0),
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1, 0),
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1  + C2, 0),
                new GePoint3d(0, checcWingWallData.Distance_W /2 + C1, 0),
            };
            GeCurveArray curveTop = GeCurveArray.createLinestringArray(top, BoundaryType.BOUNDARY_TYPE_Outer, true);
            GeCurveArray curveBot = GeCurveArray.createLinestringArray(bot, BoundaryType.BOUNDARY_TYPE_Outer, true);
            //扫掠成体
            GeRuledSweepInfo ruledSweep = new GeRuledSweepInfo(curveTop, curveBot, true);
            IGeSolidBase rightWingWall = IGeSolidBase.createGeRuledSweep(ruledSweep);
            BPGraphics rightWingWallGP = model.createPhysicalGraphics();
            rightWingWallGP.addSolid(rightWingWall);

            //基础顶面点
            GePoint3dCollection foundationTop = new GePoint3dCollection()
            {
                new GePoint3d(0, checcWingWallData.Distance_W /2 -checcWingWallData.W_innerEdge, 0),
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1 -checcWingWallData.W_innerEdge,0),
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1  + C2 + checcWingWallData.W_outerEdge, 0),
                new GePoint3d(0, checcWingWallData.Distance_W /2 + C1+ checcWingWallData.W_outerEdge, 0),
            };
            curveTop = GeCurveArray.createLinestringArray(foundationTop, BoundaryType.BOUNDARY_TYPE_Outer, true);
            //拉伸成体
            GeVec3d v3d = new GeVec3d(0, 0, -checcWingWallData.FoundationThickness);
            GeExtrusionInfo extrusionInfo = new GeExtrusionInfo(curveTop, v3d, true);
            //拉伸
            //参数:拉伸体 返回:一个 IGeSolidBase 
            IGeSolidBase rightFoundation = IGeSolidBase.createGeExtrusion(extrusionInfo);
            BPGraphics rightFoundationGp = model.createPhysicalGraphics();
            rightFoundationGp.addSolid(rightFoundation);

            BPGraphics all = Element_solid.BoolCollection(rightWingWallGP, rightFoundationGp, false);

            GePoint3dCollection point3Ds = new GePoint3dCollection()
            {
                new GePoint3d(G, checcWingWallData.Distance_W /2 + T1 - checcWingWallData.W_innerEdge, 0),
                new GePoint3d(0, checcWingWallData.Distance_W /2 - checcWingWallData.W_innerEdge, 0),
            };
            //右翼墙体积
            double gpRightWingWallVolume = 0;
            BPSolidCoreUtil.getEntityVolume(ref gpRightWingWallVolume, rightWingWallGP);
            //右基础体积
            double rightFoundationVolume = 0;
            BPSolidCoreUtil.getEntityVolume(ref rightFoundationVolume, rightFoundationGp);
            //墙长
            double wallLength = new GePoint3d(0, checcWingWallData.Distance_W / 2, 0).distance(new GePoint3d(G, checcWingWallData.Distance_W / 2 + T1, 0));
            //墙高
            double wallHeight = S;
            //底宽
            double bottomWidth = C1;
            Dictionary<string, double> keyValuePairs = new Dictionary<string, double>
            {
                { "右翼墙体积", gpRightWingWallVolume },
                { "右基础体积", rightFoundationVolume },
                { "墙长", wallLength },
                { "墙高", wallHeight },
                { "底宽", bottomWidth }
            };
            return new Tuple<BPGraphics, GePoint3dCollection, Dictionary<string, double>>(all, point3Ds, keyValuePairs);
        }

        /// <summary>
        /// 创建洞口左侧翼墙
        /// </summary>
        /// <param name="checcWingWallData">八字墙</param>
        /// <param name="coverThickness">盖板厚</param>
        /// <param name="exceedsHeight">端墙超度高度</param>
        /// <param name="angle">端墙超度高度</param>
        public static Tuple<BPGraphics, GePoint3dCollection, Dictionary<string, double>> CreateLeftCulvert(CheccWingWallData checcWingWallData)
        {
            BPProject project = BPApplication.getInstance().getProjectManager().getMainProject();
            BPModelBase model = project.getActiveModel();
            //翼墙夹角宽度
            T2 = G * Math.Tan(Math.Abs(checcWingWallData.Angle_Opposite) * Math.PI / 180);
            //翼墙顶面点
            GePoint3dCollection top = new GePoint3dCollection()
            {
                new GePoint3d(0, -checcWingWallData.Distance_W /2, S ),
                new GePoint3d(G, -checcWingWallData.Distance_W /2 - T2, checcWingWallData.H_min),
                new GePoint3d(G, -checcWingWallData.Distance_W /2 - T2 - checcWingWallData.W_topWall, checcWingWallData.H_min),
                new GePoint3d(0, -checcWingWallData.Distance_W /2 - checcWingWallData.W_topWall, S),
            };

            //翼墙低面点
            GePoint3dCollection bot = new GePoint3dCollection()
            {
                new GePoint3d(0, -checcWingWallData.Distance_W /2, 0),
                new GePoint3d(G, -checcWingWallData.Distance_W / 2 - T2, 0),
                new GePoint3d(G, -checcWingWallData.Distance_W / 2 - T2 - C2, 0),
                new GePoint3d(0, -checcWingWallData.Distance_W / 2 - C1, 0),
            };
            GeCurveArray curveTop = GeCurveArray.createLinestringArray(top, BoundaryType.BOUNDARY_TYPE_Outer, true);
            GeCurveArray curveBot = GeCurveArray.createLinestringArray(bot, BoundaryType.BOUNDARY_TYPE_Outer, true);
            //扫掠成体
            GeRuledSweepInfo ruledSweep = new GeRuledSweepInfo(curveTop, curveBot, true);
            IGeSolidBase leftWingWall = IGeSolidBase.createGeRuledSweep(ruledSweep);

            BPGraphics leftWingWallGP = model.createPhysicalGraphics();
            leftWingWallGP.addSolid(leftWingWall);
            //基础顶面点
            GePoint3dCollection foundationTop = new GePoint3dCollection()
            {
                new GePoint3d(0, -checcWingWallData.Distance_W /2 +checcWingWallData.W_innerEdge, 0),
                new GePoint3d(G, -checcWingWallData.Distance_W /2 - T2 +checcWingWallData.W_innerEdge,0),
                new GePoint3d(G, -checcWingWallData.Distance_W /2 - T2  - C2 - checcWingWallData.W_outerEdge, 0),
                new GePoint3d(0, -checcWingWallData.Distance_W /2 - C1- checcWingWallData.W_outerEdge, 0),
            };
            curveTop = GeCurveArray.createLinestringArray(foundationTop, BoundaryType.BOUNDARY_TYPE_Outer, true);
            //拉伸成体
            GeVec3d v3d = new GeVec3d(0, 0, -checcWingWallData.FoundationThickness);
            GeExtrusionInfo extrusionInfo = new GeExtrusionInfo(curveTop, v3d, true);
            IGeSolidBase leftFoundation = IGeSolidBase.createGeExtrusion(extrusionInfo);
            BPGraphics leftFoundationGp = model.createPhysicalGraphics();
            leftFoundationGp.addSolid(leftFoundation);

            BPGraphics all = Element_solid.BoolCollection(leftWingWallGP, leftFoundationGp, false);
            GePoint3dCollection point3Ds = new GePoint3dCollection()
            {
                new GePoint3d(G, -checcWingWallData.Distance_W /2 - T2 + checcWingWallData.W_innerEdge, 0),
                new GePoint3d(0, -checcWingWallData.Distance_W /2 + checcWingWallData.W_innerEdge, 0),
            };
            //翼墙体积
            double gpLeftWingWallVolume = 0;
            BPSolidCoreUtil.getEntityVolume(ref gpLeftWingWallVolume, leftWingWallGP);
            //基础体积
            double leftFoundationVolume = 0;
            BPSolidCoreUtil.getEntityVolume(ref gpLeftWingWallVolume, leftFoundationGp);
            //墙长
            double wallLength = new GePoint3d(0, -checcWingWallData.Distance_W / 2, 0).distance(new GePoint3d(G, -checcWingWallData.Distance_W / 2 - T2, 0));
            Dictionary<string, double> keyValuePairs = new Dictionary<string, double>();
            keyValuePairs.Add("左翼墙体积", gpLeftWingWallVolume);
            keyValuePairs.Add("左基础体积", leftFoundationVolume);
            //keyValuePairs.Add("左墙长", wallLength);
            return new Tuple<BPGraphics, GePoint3dCollection, Dictionary<string, double>>(all, point3Ds, keyValuePairs);
        }

        /// <summary>
        /// 铺砌和截水墙
        /// </summary>
        /// <param name="checcWingWallData"></param>
        /// <param name="right"></param>
        /// <param name="left"></param>
        /// <param name="checcWingWallData.PaveOffset"></param>
        public static Tuple<BPGraphics, Dictionary<string, double>> CreatePave(CheccWingWallData checcWingWallData, GePoint3dCollection right, GePoint3dCollection left)
        {
            BPProject project = BPApplication.getInstance().getProjectManager().getMainProject();
            BPModelBase model = project.getActiveModel();
            #region 铺砌
            //铺砌顶面点
            GePoint3dCollection paveTop = new GePoint3dCollection()
            {
                right[0],
                right[1],
                left[1],
                left[0],
            };
            //判断是否有铺砌加长
            if (checcWingWallData.PaveOffset > 0)
            {
                //顶面
                paveTop.Add(new GePoint3d(left[0].x, left[0].y - checcWingWallData.W_innerEdge - C2, left[0].z));
                paveTop.Add(new GePoint3d(left[0].x + checcWingWallData.PaveOffset, left[0].y - checcWingWallData.W_innerEdge - C2, left[0].z));
                paveTop.Add(new GePoint3d(right[0].x + checcWingWallData.PaveOffset, right[0].y + checcWingWallData.W_innerEdge + C2, right[0].z));
                paveTop.Add(new GePoint3d(right[0].x, right[0].y + checcWingWallData.W_innerEdge + C2, right[0].z));
            }
            GeCurveArray curveArray = GeCurveArray.createLinestringArray(paveTop, BoundaryType.BOUNDARY_TYPE_Outer, true);
            double angle = Math.Atan(checcWingWallData.PaveSlope) * 180 / Math.PI;
            //坡度，矩阵变化
            GeRotMatrix rotMatrix = GeRotMatrix.createByVectorAndRotationAngle(new GeVec3d(0, 1, 0), angle / 57.2958);
            GeTransform transform = GeTransform.create(rotMatrix, GePoint3d.createByZero());
            curveArray.setByTransform(transform);
            //拉伸成体
            GeVec3d v3d = new GeVec3d(0, 0, -checcWingWallData.Thickness_pave);
            GeExtrusionInfo extrusionInfo = new GeExtrusionInfo(curveArray, v3d, true);
            IGeSolidBase pave = IGeSolidBase.createGeExtrusion(extrusionInfo);
            BPGraphics paveGp = model.createPhysicalGraphics();
            paveGp.addSolid(pave);
            #endregion

            #region 截水墙
            //判断是否有铺砌加长
            if (checcWingWallData.PaveOffset > 0)
            {
                double Rx = right[0].x + checcWingWallData.PaveOffset;
                double Ry = right[0].y + checcWingWallData.W_innerEdge + C2;
                double Rz = right[0].z;
                right[0].set(Rx, Ry, Rz);
                double Lx = left[0].x + checcWingWallData.PaveOffset;
                double Ly = left[0].y - checcWingWallData.W_innerEdge - C2;
                double Lz = left[0].z;
                left[0].set(Lx, Ly, Lz);
            }
            else
            {
                double Rx = right[0].x;
                double Ry = right[0].y + checcWingWallData.W_innerEdge + C2;
                double Rz = right[0].z;
                right[0].set(Rx, Ry, Rz);
                double Lx = left[0].x;
                double Ly = left[0].y - checcWingWallData.W_innerEdge - C2;
                double Lz = left[0].z;
                left[0].set(Lx, Ly, Lz);
            }

            GePoint3dCollection cutoffWallTop = new GePoint3dCollection()
            {
                right[0],
                new GePoint3d(right[0].x  - checcWingWallData.W_CutoffWall, right[0].y, right[0].z),
                new GePoint3d(left[0].x - checcWingWallData.W_CutoffWall, left[0].y, left[0].z),
                left[0],
            };
            curveArray = GeCurveArray.createLinestringArray(cutoffWallTop, BoundaryType.BOUNDARY_TYPE_Outer, true);
            curveArray.setByTransform(transform);
            //拉伸成体
            v3d = new GeVec3d(0, 0, -checcWingWallData.H_CutoffWall);
            extrusionInfo = new GeExtrusionInfo(curveArray, v3d, true);
            IGeSolidBase cutoffWall = Element_solid.getTensileBody(extrusionInfo);
            BPGraphics cutoffWallGp = model.createPhysicalGraphics();
            cutoffWallGp.addSolid(cutoffWall);

            BPGraphics graphics = Element_solid.BoolCollection(paveGp, cutoffWallGp, false);
            #endregion
            //铺砌体积
            double paveVolume = 0;
            BPSolidCoreUtil.getEntityVolume(ref paveVolume, paveGp);
            //截水墙体积
            double cutoffWallVolume = 0;
            BPSolidCoreUtil.getEntityVolume(ref cutoffWallVolume, cutoffWallGp);
            //截水墙长
            double cutoffWallLength = right[0].distance(left[0]);
            Dictionary<string, double> keyValuePairs = new Dictionary<string, double>();
            keyValuePairs.Add("铺砌体积", paveVolume);
            keyValuePairs.Add("截水墙体积", cutoffWallVolume);
            keyValuePairs.Add("截水墙长", cutoffWallLength);
            return new Tuple<BPGraphics, Dictionary<string, double>>(graphics, keyValuePairs);
        }

        public static Tuple<BPGraphicsCollection, Dictionary<string, double>> create(CheccWingWallData checcWingWallData, double coverThickness, double exceedsHeight, double angle)
        {
            CheccWingWallData checcWingWall = new CheccWingWallData();
            checcWingWall.Slope_subgrade = checcWingWallData.Slope_subgrade;                                                         //路基边坡坡度(1:m) //路基边坡坡度(1:m) 
            checcWingWall.PaveSlope = checcWingWallData.PaveSlope * 0.01;                                                                   //左洞洞口铺砌坡度:向外方向下坡为正 上坡为负, 坡度值为沿着涵洞轴线方向
            checcWingWall.Thickness_pave = checcWingWallData.Thickness_pave * Culvert_Help.GeneralHelpers.UOR;                                               //铺砌厚度(m) 
            checcWingWall.PaveOffset = checcWingWallData.PaveOffset * Culvert_Help.GeneralHelpers.UOR;                                                        //左洞铺砌外延(m)
            checcWingWall.H_CutoffWall = checcWingWallData.H_CutoffWall * Culvert_Help.GeneralHelpers.UOR;                                                    //截水墙高（含铺砌高度）(m)
            checcWingWall.W_CutoffWall = checcWingWallData.W_CutoffWall * Culvert_Help.GeneralHelpers.UOR;                                                   //截水墙厚(m)
            checcWingWall.Distance_W = checcWingWallData.Distance_W / Math.Abs(Math.Cos(Math.PI * angle / 180)) * Culvert_Help.GeneralHelpers.UOR;                        //左洞两侧八字墙最高截面处沿桩号的净距//净跨
            checcWingWall.Distance_H = checcWingWallData.Distance_H * Culvert_Help.GeneralHelpers.UOR;                                                          //右洞两侧八字墙最高截面处沿桩号的净距  //净高
            checcWingWall.Angle_Favorable = checcWingWallData.Angle_Favorable;                                         //顺翼墙外偏角
            checcWingWall.Angle_Opposite = checcWingWallData.Angle_Opposite;                                          //逆翼墙外偏角
            checcWingWall.W_topWall = checcWingWallData.W_topWall * Culvert_Help.GeneralHelpers.UOR;                                                        //八字墙顶宽a(m)
            checcWingWall.H_min = checcWingWallData.H_min * Culvert_Help.GeneralHelpers.UOR;                                                                //八字墙最低截面高度h(m)
            checcWingWall.W_innerEdge = checcWingWallData.W_innerEdge * Culvert_Help.GeneralHelpers.UOR;                                                     //基础内侧襟边e1(m)
            checcWingWall.W_outerEdge = checcWingWallData.W_outerEdge * Culvert_Help.GeneralHelpers.UOR;                                                     //基础外侧襟边e2(m)
            checcWingWall.Slope_outerVerticalWall = checcWingWallData.Slope_outerVerticalWall;                             //翼墙垂直背坡(n:1) 
            checcWingWall.FoundationThickness = checcWingWallData.FoundationThickness * Culvert_Help.GeneralHelpers.UOR;                                     //翼墙基础厚度d(m)
            checcWingWall.BurialDepth = checcWingWallData.BurialDepth * Culvert_Help.GeneralHelpers.UOR;                                                          //基础入土深度h(cm)

            //右侧翼墙基础最外侧两点
            Tuple<BPGraphics, GePoint3dCollection, Dictionary<string, double>> right = CreateRightCulvert(checcWingWall, coverThickness * Culvert_Help.GeneralHelpers.UOR, exceedsHeight * Culvert_Help.GeneralHelpers.UOR);
            BPGraphics graphic1Right = right.Item1;

            //左侧翼墙基础最外侧两点
            Tuple<BPGraphics, GePoint3dCollection, Dictionary<string, double>> left = CreateLeftCulvert(checcWingWall);
            BPGraphics graphic1Left = left.Item1;

            //铺砌截水墙
            Tuple<BPGraphics, Dictionary<string, double>> bPGraphics = CreatePave(checcWingWall, right.Item2, left.Item2);
            BPGraphics graphic = bPGraphics.Item1;

            //旋转洞口角度
            graphic1Right = Helper.unitRotation(graphic1Right, angle);
            graphic1Left = Helper.unitRotation(graphic1Left, angle);
            graphic = Helper.unitRotation(graphic, angle);
            //相对于第一种只是修改了遍历的方法
            foreach (string key in left.Item3.Keys)
            {
                if (!right.Item3.ContainsKey(key))
                    right.Item3.Add(key, left.Item3[key]);
            }
            foreach (string key in bPGraphics.Item2.Keys)
            {
                if (!right.Item3.ContainsKey(key))
                    right.Item3.Add(key, bPGraphics.Item2[key]);
            }

            //返回八字墙底面四个点的平面
            GePoint3dCollection gePoint3dCollection = new GePoint3dCollection();
            foreach (var item in left.Item2)
            {
                gePoint3dCollection.Add(item);
            }
            for (int i = 1; i <= right.Item2.Count; i++)
            {
                gePoint3dCollection.Add(right.Item2[right.Item2.Count - i]);
            }

            GeCurveArray geCurveArray = GeCurveArray.createLinestringArray(gePoint3dCollection, BoundaryType.BOUNDARY_TYPE_Outer, true);
            BPGraphics plan = GeneralHelpers.Model2D.createPhysicalGraphics();
            plan.addCurveArray(geCurveArray);
            plan = Helper.unitRotation(plan, angle);
            BPGraphicsCollection bPGraphics1 = new BPGraphicsCollection { graphic1Right, graphic1Left, graphic, plan };
            return new Tuple<BPGraphicsCollection, Dictionary<string, double>>(bPGraphics1, right.Item3);
        }
    }
}
